﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media.Media3D;
using System.Windows.Media;
using System.Windows;
using System.Data;
using System.Reflection;
using System.Collections;
using CrazyWorship1.Transitions;
using CrazyWorship1.Controllers;
using CrazyWorship1.Assets;
using System.Globalization;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using CrazyWorship1.Class_Files.PropertyHandler;


namespace CrazyWorship1.Creators
{
    public abstract class CreateAllBase:ICreator
    {

        #region Public Properties

        Dictionary<Guid, Visual> textBlocks;
        public Dictionary<Guid, Visual> TextBlocks
        {
            get { return textBlocks; }
        }


        Dictionary<Guid, GeometryModel3D> textPanes;
        public Dictionary<Guid, GeometryModel3D> TextPanes
        {
            get
            {
                return textPanes;
            }
        }

        State _currentState;
        public State CurrentState
        {
            get
            {
                return _currentState;
            }
            set
            {
                _currentState = value;
            }
        }

        private Model3DGroup mainModel3DGroup, textModel3DGroup, bgModel3DGroup, fgModel3DGroup;

        public Model3DGroup TextModelGroup
        {
            get
            {
                return textModel3DGroup;
            }
        }

        public Model3DGroup BackgroundModelGroup
        {
            get
            {
                return bgModel3DGroup;
            }
        }



        #endregion


        #region Transitions
        Dictionary<Guid, string> inTransitions;
        Dictionary<Guid, string> outTransitions;
        string _songIn, _songOut;

        public void SetIn(Guid lyric, string nameOfTransition)
        {
            inTransitions.Add(lyric, nameOfTransition);
        }
        public void SetSongIn(string nameOfTransition)
        {
            _songIn = nameOfTransition;
        }
        public void SetSongOut(string nameOfTransition)
        {
            _songOut = nameOfTransition;
        }
        public void SetOut(Guid lyric, string nameOfTransition)
        {
            outTransitions.Add(lyric, nameOfTransition);
        }

        public BaseTransitionIn GetInTransition(Guid g)
        {
            BaseTransitionIn tr = CurrentState.GetInTransition(inTransitions[g]);
            tr.PrepareTransition(this);
            return tr;
        }
        public BaseTransitionOut GetOutTransition(Guid g)
        {
            BaseTransitionOut tr = CurrentState.GetOutTransition(outTransitions[g]);
            tr.PrepareTransition(this);
            return tr;
        }
        public BaseSongTransitionIn GetSongInTransition()
        {
            BaseSongTransitionIn tr = CurrentState.GetSongInTransition(_songIn);
            tr.PrepareTransition(this);
            return tr;
        }
        public BaseSongTransitionOut GetSongOutTransition()
        {
            BaseSongTransitionOut tr = CurrentState.GetSongOutTransition(_songOut);
            tr.PrepareTransition(this);
            return (BaseSongTransitionOut)tr;
        }


        private void CurrentState_OnStartSongChange(object sender, EventArgs e)
        {

            BaseSongTransitionOut r = GetSongOutTransition();
            r.OnTransitionDone += new EventHandler(r_OnTransitionDone);
            r.Go();

        }

        void r_OnTransitionDone(object sender, EventArgs e)
        {
            CurrentState.OnLyricChanged -= new EventHandler(CurrentState_OnLyricChanged);
            CurrentState.OnStartSongChange -= new EventHandler(CurrentState_OnStartSongChange);
            CreatorDone();
        }
        public event EventHandler OnCreatorDone;

        private void CurrentState_OnLyricChanged(object sender, EventArgs e)
        {
            BaseTransitionOut a = null;
            if (CurrentState.PreviousLyric != null)
            {

                a = GetOutTransition(CurrentState.PreviousLyric.LyricID);
            }
            BaseTransitionIn b = GetInTransition(CurrentState.CurrentLyric.LyricID);
            if (CurrentState.PreviousLyric != null)
                a.Go();
            b.Go();
        }


        #endregion


        #region Panels

        public GeometryModel3D CreateEmptyPanel(Model3DGroup m3DGroup, Point3D p, Rotation3D rot, Point3D center,Vector3D scale)
        {
            GeometryModel3D gm3D = new GeometryModel3D();
            MeshGeometry3D mg3D = new MeshGeometry3D();
            mg3D.Positions.Add(new Point3D(-1, -1, 0));
            mg3D.Positions.Add(new Point3D(1, -1, 0));
            mg3D.Positions.Add(new Point3D(-1, 1, 0));
            mg3D.Positions.Add(new Point3D(1, 1, 0));

            mg3D.Normals.Add(new Vector3D(0, 0, 1));
            mg3D.Normals.Add(new Vector3D(0, 0, 1));
            mg3D.Normals.Add(new Vector3D(0, 0, 1));
            mg3D.Normals.Add(new Vector3D(0, 0, 1));

            mg3D.TextureCoordinates.Add(new Point(0, 1));
            mg3D.TextureCoordinates.Add(new Point(1, 1));
            mg3D.TextureCoordinates.Add(new Point(0, 0));
            mg3D.TextureCoordinates.Add(new Point(1, 0));

            mg3D.TriangleIndices.Add(0);
            mg3D.TriangleIndices.Add(1);
            mg3D.TriangleIndices.Add(2);
            mg3D.TriangleIndices.Add(1);
            mg3D.TriangleIndices.Add(3);
            mg3D.TriangleIndices.Add(2);
            gm3D.Transform = new Transform3DGroup();


            Transform3DGroup baseGroup = ((Transform3DGroup)gm3D.Transform);

            Transform3DGroup staticGroup = new Transform3DGroup();
            Transform3DGroup transitionGroup = new Transform3DGroup();
            Transform3DGroup effectsGroup = new Transform3DGroup();
            staticGroup.Children.Add(new TranslateTransform3D(p.X, p.Y, p.Z));
           staticGroup.Children.Add(new RotateTransform3D(rot, center));
            staticGroup.Children.Add(new ScaleTransform3D(scale));
          // staticGroup.Freeze();
            baseGroup.Children.Add(staticGroup);
            baseGroup.Children.Add(transitionGroup);
            baseGroup.Children.Add(effectsGroup);

            

            gm3D.Geometry = mg3D;


           

            return gm3D;
        }
        public void CreateTextPanel(Model3DGroup m3DGroup, Guid lyricId, string text, string style,Point3D p,Rotation3D rot,Point3D center,Vector3D scale)
        {

            GeometryModel3D gm3D =CreateEmptyPanel(m3DGroup, p, rot, center,scale);

           /// RenderTargetBitmap rt = new RenderTargetBitmap(1000,1000,100,100,PixelFormats.Pbgra32);
          
            VisualBrush vb = new VisualBrush();
            vb.Stretch = Stretch.None;
            DiffuseMaterial dm = new DiffuseMaterial();
            
            Visual tb;
            if (false)
            {
                //FontStyle fontStyle = FontStyles.Normal;
                //FontWeight fontWeight = FontWeights.Medium;
                //FormattedText formattedText = new FormattedText(
                //               text,
                //               CultureInfo.GetCultureInfo("en-us"),
                //               FlowDirection.LeftToRight,
                //               new Typeface(
                //                   new FontFamily("Arial"),
                //                   fontStyle,
                //                   fontWeight,
                //                   FontStretches.Normal),
                //               0.05,
                //               System.Windows.Media.Brushes.Black // This brush does not matter since we use the geometry of the text. 
                //               );
                ////   formattedText.MaxLineCount = 2;
                ////  formattedText.LineHeight = 10;
                //formattedText.MaxTextWidth = 0.3;
                //formattedText.MaxTextHeight = 1;
                //formattedText.TextAlignment = TextAlignment.Center;

                //Geometry _textGeometry = formattedText.BuildGeometry(new System.Windows.Point(0, 0));
                //PathGeometry pth = _textGeometry.GetFlattenedPathGeometry(0.00001, ToleranceType.Absolute).Clone();
                //Random r = new Random();
                //double max = 0.000000000001;
                
                //foreach (PathFigure fig in pth.Figures)
                //{

                //    //fig.StartPoint = new Point(fig.StartPoint.X + (r.Next() * 0.000001), fig.StartPoint.Y + (r.Next() * 0.000001));
                //    fig.StartPoint = new Point(fig.StartPoint.X + (r.Next() * max), fig.StartPoint.Y + (r.Next() * max));
                //    foreach (PathSegment seg in fig.Segments)
                //    {
                //        if (seg is PolyLineSegment)
                //        {
                //            PolyLineSegment g = seg as PolyLineSegment;
                //            for (int i = 0; i < g.Points.Count; i++)
                //            {
                //                g.Points[i] = new Point(g.Points[i].X + (r.Next() * max), g.Points[i].Y + (r.Next() * max));

                //            }
                //        }
                //        if (seg is ArcSegment)
                //        {
                //            ArcSegment g = seg as ArcSegment;
                //            g.Point = new Point(g.Point.X + (r.Next() * max), g.Point.Y);
                //        }
                //        if (seg is BezierSegment)
                //        {
                //            BezierSegment g = seg as BezierSegment;
                //            g.Point3 = new Point(g.Point3.X + (r.Next() * max), g.Point3.Y);
                //        }
                //        if (seg is LineSegment)
                //        {
                //            LineSegment g = seg as LineSegment;
                //            g.Point = new Point(g.Point.X + (r.Next() * max), g.Point.Y);
                //        }
                //    }
                //}
                ////pth.Freeze();
                //tb = new Path();
                //((Path)tb).Stroke = Brushes.Red;
                //((Path)tb).StrokeThickness = 0.001;

                //((Path)tb).Fill = Brushes.Blue;
                //((Path)tb).Data = pth;
                
              
            }
            else
            {
               tb = new TextBlock();
               TextBlock textBlock = tb as TextBlock;

               textBlock.Name = "tb" + lyricId.ToString().Replace("-", "");
               textBlock.Text = text;

               textBlock.Style = (Style)CurrentState.Viewers[0].Resources[style];
               textBlock.TextWrapping = TextWrapping.Wrap;
               textBlock.Height = 1;
               textBlock.Width = 1;
               textBlock.TextTrimming = TextTrimming.None;
               textBlock.TextAlignment = TextAlignment.Center;
              
                
            }

            textBlocks.Add(lyricId, tb);
           
          
            
            // Build the geometry object that represents the text hightlight.
       //     if (Highlight == true)
        //    {
       //         _textHighLightGeometry = formattedText.BuildHighlightGeometry(new System.Windows.Point(0, 0));
       //     }


            //rt.Render(tb);
            
           // ImageBrush ib=new ImageBrush(rt);
            //ib.Opacity=0;

            vb.Visual = tb;
            vb.Opacity = 0;
            dm.Brush = vb;
            //dm.Brush = ib;
            gm3D.Material = dm;
          
            textPanes.Add(lyricId, gm3D);
            m3DGroup.Children.Add(gm3D);
         //   m3DGroup.Children.Add(new AmbientLight(Color.FromRgb(255, 255, 255)));

        }
     
#endregion


        public void StartSong()
        {

            CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);

            Viewport3D vpScreen1 = CurrentState.Viewers[0].Viewport3D;
            Viewport3D vpScreen2 = CurrentState.Viewers[1].Viewport3D;
            vpScreen1.ClipToBounds = false;
            vpScreen2.ClipToBounds = false;
            vpScreen1.IsHitTestVisible = false;
            vpScreen2.IsHitTestVisible = false;
            RenderOptions.SetEdgeMode(vpScreen2, EdgeMode.Aliased);
            RenderOptions.SetEdgeMode(vpScreen1, EdgeMode.Aliased);
            ModelVisual3D mv3DScreen1 = new ModelVisual3D();
            ModelVisual3D mv3DScreen2 = new ModelVisual3D();

            mainModel3DGroup = new Model3DGroup();
            textModel3DGroup=new Model3DGroup();
            bgModel3DGroup=new Model3DGroup();
            fgModel3DGroup = new Model3DGroup();
            vpScreen2.Children.Clear();
            vpScreen1.Children.Clear();
            vpScreen1.Children.Add(mv3DScreen1);
            vpScreen2.Children.Add(mv3DScreen2);
            mv3DScreen1.Content = mainModel3DGroup;
            mv3DScreen2.Content = mainModel3DGroup;
            
            mainModel3DGroup.Children.Add(bgModel3DGroup); 
            
            mainModel3DGroup.Children.Add(textModel3DGroup);

            mainModel3DGroup.Children.Add(fgModel3DGroup);

            textBlocks = new Dictionary<Guid, Visual>();
            textPanes = new Dictionary<Guid, GeometryModel3D>();
            inTransitions = new Dictionary<Guid, string>();
            outTransitions = new Dictionary<Guid, string>();
            
            SetProperties();
            SetupPanes();
            SetupAssets();
            SetupControllers();
            CurrentState.OnLyricChanged += new EventHandler(CurrentState_OnLyricChanged);
            CurrentState.OnStartSongChange += new EventHandler(CurrentState_OnStartSongChange);

        }

        #region Controllers

        Dictionary<Guid, ControllerBase> controllers;
        private void SetupControllers()
        {
             DataView dv = new DataView(CurrentState.SongDB.Controllers, "SongID='" + CurrentState.CurrentSong.SongID.ToString() + "'", "", DataViewRowState.CurrentRows);
           
            controllers = new Dictionary<Guid, ControllerBase>();
            foreach (DataRowView r in dv)
            {
                
                SongDB.ControllersRow w=((SongDB.ControllersRow)r.Row);
                ControllerBase cb=CurrentState.GetController(w.Name);
                controllers.Add(w.ControllerID, cb);

                cb.ParentCreator = this;
                 DataView dv2 = new DataView(CurrentState.SongDB.ControllerProperties, "ControllerID='" + w.ControllerID + "'", "", DataViewRowState.CurrentRows);

                 foreach (DataRowView drv in dv2)
                 {
                     SongDB.ControllerPropertiesRow w2 = ((SongDB.ControllerPropertiesRow)drv.Row);
                     cb.SetProperty(w2.PropertyName, w2.Value);
                 }
                 cb.Go();
            }
        }

        #endregion

        #region Assets

        Dictionary<Guid, AssetBase> assets;
        Dictionary<String, AssetBase> assetNames;
        private void SetupAssets()
        {
            DataView dv = new DataView(CurrentState.SongDB.Assets, "SongID='" + CurrentState.CurrentSong.SongID.ToString() + "'", "", DataViewRowState.CurrentRows);
            assetNames = new Dictionary<string, AssetBase>();
            assets = new Dictionary<Guid, AssetBase>();
            foreach (DataRowView r in dv)
            {
                SongDB.AssetsRow w = ((SongDB.AssetsRow)r.Row);
                AssetBase cb = CurrentState.GetAsset(w.Name);
                assets.Add(w.AssetID, cb);
                
                cb.ParentCreator = this;
                DataView dv2 = new DataView(CurrentState.SongDB.AssetProperties, "AssetID='" + w.AssetID + "'", "", DataViewRowState.CurrentRows);

                foreach (DataRowView drv in dv2)
                {
                    SongDB.AssetPropertiesRow w2 = ((SongDB.AssetPropertiesRow)drv.Row);
                    cb.SetProperty(w2.PropertyName, w2.Value);
                    if (w2.PropertyName == "Name")
                    {
                        assetNames.Add(w2.Value, cb);
                    }
                }
                cb.Go();
            }
        }

        public AssetBase GetAssetByName(string key)
        {
            return assetNames[key];
        }
        
#endregion


        public void CreatorDone()
        {
            if (OnCreatorDone != null)
                OnCreatorDone(this, new EventArgs());
        }
        protected void CleanUpSong()
        {
        

        }


        public Dictionary<string, PropertyHandlerControl> PropertyHandlers
        {
            get
            {
                Dictionary<string, PropertyHandlerControl> dict = new Dictionary<string, PropertyHandlerControl>();

                Type t = this.GetType();
                PropertyInfo[] p = t.GetProperties();
                //  ArrayList properties = new ArrayList();

                foreach (PropertyInfo pi in p)
                {
                    if (pi.IsDefined(typeof(DataAttribute), true) && pi.CanWrite)
                    {
                        object[] fields = pi.GetCustomAttributes(typeof(DataAttribute), true);
                        foreach (DataAttribute d in fields)
                        {

                            dict.Add(d.FieldName, d.Handler);
                            
                            
                        }

                    }
                }
                return dict;
            }
        }
        private void SetProperties()
        {
            DataView dv = new DataView(CurrentState.SongDB.CreatorAppProperties, "SongID='" + CurrentState.CurrentSong.SongID.ToString() + "'", "", DataViewRowState.CurrentRows);
            foreach (DataRowView d in dv)
            {
                SongDB.CreatorAppPropertiesRow t = (SongDB.CreatorAppPropertiesRow)d.Row;
                SetProperty(t.PropertyName, t.Value);
            }
        }
        private void SetProperty(string name, string value)
        {
            Type t = this.GetType();
            PropertyInfo[] p = t.GetProperties();
          //  ArrayList properties = new ArrayList();

            foreach (PropertyInfo pi in p)
            {
                if (pi.IsDefined(typeof(DataAttribute), true) && pi.CanWrite)
                {
                    object[] fields = pi.GetCustomAttributes(typeof(DataAttribute), true);
                    foreach (DataAttribute d in fields)
                    {
                        if (d.FieldName == name)
                        {
                            pi.SetValue(this, value, null);
                        }
                    }

                }
            }
        }
        public virtual void SetupPanes()
        {
        }
        Model3DCollection mg;
        protected virtual void CompositionTarget_Rendering(object sender, EventArgs e)
        {

            mg= textModel3DGroup.Children;
            SceneHelper.SceneSortingHelper.AlphaSort(((PerspectiveCamera)CurrentState.Viewers[0].Viewport3D.Camera).Position, mg, Transform3D.Identity);
        }
    }
}
